package com.owc.job;

import com.owc.common.enums.OrderType;
import com.owc.common.redis.CacheBuildKey;
import com.owc.common.redis.RedisUtil;
import com.owc.common.tool.DateUtils;
import com.owc.common.tool.UtilsService;
import com.owc.dao.ProductMapper;
import com.owc.domain.entity.IncomeRecord;
import com.owc.domain.entity.Order;
import com.owc.domain.entity.Product;
import com.owc.service.app.OrderService;
import com.owc.service.impl.app.TransactionService;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.JobHandler;
import com.xxl.job.core.log.XxlJobLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static com.owc.common.tool.DateUtils.*;

@Component
@Slf4j
@JobHandler(value = "IncomeJobHandler")
public class IncomeJob extends IJobHandler {

    @Autowired
    private OrderService orderService;
    @Autowired
    private TransactionService transactionService;

    @Resource
    private ProductMapper productMapper;


    private void lock(){
        XxlJobLogger.log("Lock income job..");
        RedisUtil.getInstance().set(CacheBuildKey.buildIncomeJobLockKey(),1);
    }

    private boolean getLock(){
        return RedisUtil.getInstance().get(CacheBuildKey.buildIncomeJobLockKey()) == null;
    }

    private void unlock(){
        XxlJobLogger.log("Unlock income job..");
        RedisUtil.getInstance().del(CacheBuildKey.buildIncomeJobLockKey());
    }

    /**
     * 结算收益
     * 过期时间: 2020-03-10 12:32:14
     * 当前时间：2020-03-11 00:02:00
     * 当前时间 - 1 > 过期时间 ？ 过期 : 未过期
     */
    @Override
    public ReturnT<String> execute(String s) throws Exception {
        if(!getLock()){
            XxlJobLogger.log("任务执行中......");
            return ReturnT.FAIL;
        }
        try {
            lock();
            List<Order> orders = orderService.getValidOrderList(OrderType.VALID_TYPE);
            if(orders == null || orders.isEmpty()){
                XxlJobLogger.log("无有效订单,结束执行收益结算任务");
                return ReturnT.SUCCESS;
            }

            String date = DateUtils.formatYMD(returnPreviousDay(new Date()));

            //已过期订单集合
            List<Order> updateOrderList = new ArrayList<>();
            //发放收益集合
            List<IncomeRecord> incomeRecords = new ArrayList<>();
            for (Order order : orders) {
                //判断订单是否过期
                long expireTime = Long.parseLong(getFormat(YYYYMMDD).format(parseTimeString2Date(order.getExpireTime(),DATE_FORMAT_YYYY_MM_DD_HH_MM_SS)));
                //T+1 时间
                long yesterdayTime = Long.parseLong(getFormat(YYYYMMDD).format(returnPreviousDay(new Date())));
                if(expireTime <= yesterdayTime){
                    XxlJobLogger.log("当前时间:[{}] 用户:[{}] 过期时间:[{}]. 已过期",yesterdayTime,order.getBuyUserName(),order.getExpireTime());
                    //订单已过期
                    Order updateOrder = new Order();
                    updateOrder.setStatus(OrderType.INVALID_TYPE.getType());
                    updateOrder.setId(order.getId());
                    updateOrder.setIncome(order.getIncome());
                    updateOrderList.add(updateOrder);
                    continue;
                }
                if(RedisUtil.getInstance().isMember(CacheBuildKey.buildSettlementIncomeKey(date),order.getBuyUserId() + "")){
                    XxlJobLogger.log("日期:[{}] 用户:[{}] 已发放收益,跳过执行",date,order.getBuyUserName());
                    continue;
                }

                Product product = productMapper.selectByPrimaryKey(order.getProductId());
                if(product == null){
                    XxlJobLogger.log("异常的产品ID:[{}]",order.getProductId());
                    continue;
                }
                //未过期,则发放收益
                BigDecimal income = calculationIncome(product,order.getAmount());
                updateOrderList.add(loadAlreadyIncome(order.getId(),(order.getIncome() == null ? BigDecimal.ZERO :order.getIncome()).add(income),order.getStatus()));
                XxlJobLogger.log("用户:[{}] date:[{}] 发放收益:[{}]",order.getBuyUserName(),date,income);
                incomeRecords.add(loadIncomeModel(income,order,date));
            }

            transactionService.saveData(updateOrderList,incomeRecords);

            XxlJobLogger.log("日期:[{}] 发放收益完毕,发放用户数:[{}]",date,incomeRecords.size());
        }finally {
            unlock();
        }
        return ReturnT.SUCCESS;
    }

    private Order loadAlreadyIncome(Long id, BigDecimal income,Integer status) {
        Order order = new Order();
        order.setId(id);
        order.setIncome(income);
        order.setStatus(status);
        return order;
    }

    private IncomeRecord loadIncomeModel(BigDecimal income, Order order,String date) {
        IncomeRecord record = new IncomeRecord();
        record.setDay(DateUtils.formatYMD(new Date()));
        record.setIncome(income);
        record.setOrderId(order.getOrderId());
        record.setTime(DateUtils.formatYMDHMS(new Date()));
        record.setUserId(order.getBuyUserId());
        record.setDay(date);
        record.setTokenId(order.getIncomeId());
        record.setTokenName(order.getIncomeName());
        return record;
    }

    /**
     * 计算收益
     * 每日收益=投资币种数量*年化收益率*附加参数/365
     */
    private BigDecimal calculationIncome(Product product,BigDecimal amount){
        int digit = 4;
        return amount.multiply(product.getRate()
                .divide(new BigDecimal(100),digit, RoundingMode.HALF_EVEN))
                .multiply(new BigDecimal(product.getAttach()))
                .divide(new BigDecimal(365),digit,RoundingMode.HALF_EVEN);
    }

}
